package stanPaysNg

import (
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"time"
)

type StanPayNgService interface {
	Payment(request PaymentRequest) (PaymentResponse, error)
	VerifySign(jsonData string) (bool, error)
	Disbursement(request DisbursementRequest) (DisbursementResponse, error)
	DisbursementCallbackVerify(jsonData string) (bool, error)
	Balance() (BalanceResponse, error)
	SetPrivateKey(key string) StanPayNgService
	SetPublicKey(Key string) StanPayNgService
	SetPaymentUrl(url string) StanPayNgService
	SetDisbursementUrl(url string) StanPayNgService
}

type StanpayNg struct {
	MchId           string
	privateKey      string
	publicKey       string
	paymentUrl      string
	disbursementUrl string
}

func NewStanPayNg(mchid string) StanPayNgService {
	return &StanpayNg{
		MchId:           mchid,
		paymentUrl:      PaymentUrl,
		disbursementUrl: DisbursementUrl,
	}
}

func (s *StanpayNg) Payment(request PaymentRequest) (resp PaymentResponse, err error) {
	request.MchId = s.MchId
	key := fmt.Sprintf("-----BEGIN PRIVATE KEY-----\n%s\n-----END PRIVATE KEY-----", s.getPrivateKey())
	sign, err := request.GetSign(key)
	if err != nil {
		return
	}
	request.Sign = sign
	response, err := sendPostRequest(s.paymentUrl, request)
	if err != nil {
		return
	}

	resp = PaymentResponse{}
	err = json.Unmarshal(response, &resp)
	if err != nil {
		return
	}
	if resp.ResponseCode != ResponseCodeSUCCESS {
		err = errors.New(resp.ResponseDesc)
		return
	}
	return
}

func (s *StanpayNg) VerifySign(jsonData string) (resp bool, err error) {
	if jsonData == "" {
		return false, err
	}

	var _data CallbackRequest
	err = json.Unmarshal([]byte(jsonData), &_data)
	if err != nil {
		return
	}
	//if _data.NotifyCode != ResponseCodeSUCCESS {
	//	err = errors.New(_data.NotifyDesc)
	//}
	// 验证
	key := fmt.Sprintf("-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----", s.getPublicKey())
	resp, err = _data.verifySign(key)
	return
}

func (s *StanpayNg) Disbursement(request DisbursementRequest) (resp DisbursementResponse, err error) {
	request.MchId = s.MchId
	// 尼日利亚银行账号
	request.Method = PaymentMethodCARD
	key := fmt.Sprintf("-----BEGIN PRIVATE KEY-----\n%s\n-----END PRIVATE KEY-----", s.getPrivateKey())
	sign, err := request.GetSign(key)
	if err != nil {
		return
	}
	request.Sign = sign
	response, err := sendPostRequest(s.disbursementUrl, request)
	if err != nil {
		return
	}
	resp = DisbursementResponse{}
	err = json.Unmarshal(response, &resp)
	if err != nil {
		return
	}
	if resp.ResponseCode != ResponseCodeSUCCESS {
		err = errors.New(resp.ResponseDesc)
		return
	}
	return
}

func (s *StanpayNg) DisbursementCallbackVerify(jsonData string) (resp bool, err error) {
	if jsonData == "" {
		return false, err
	}

	var _data DisbursementCallbackRequest
	err = json.Unmarshal([]byte(jsonData), &_data)
	if err != nil {
		return
	}
	//if _data.NotifyCode != ResponseCodeSUCCESS {
	//	err = errors.New(_data.NotifyDesc)
	//}
	// 验证
	key := fmt.Sprintf("-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----", s.getPublicKey())
	resp, err = _data.verifySign(key)
	return
}

func (s *StanpayNg) Balance() (resp BalanceResponse, err error) {
	request := BalanceRequest{
		MchId:    s.MchId,
		DateTime: time.Now().Format("20060102150405"),
	}
	request.MchId = s.MchId
	key := fmt.Sprintf("-----BEGIN PRIVATE KEY-----\n%s\n-----END PRIVATE KEY-----", _privateKey)
	sign, err := request.GetSign(key)
	if err != nil {
		return
	}
	request.Sign = sign
	response, err := sendPostRequest(BalanceUrl, request)
	if err != nil {
		return
	}

	resp = BalanceResponse{}
	err = json.Unmarshal(response, &resp)
	if err != nil {
		return
	}
	if resp.ResponseCode != ResponseCodeSUCCESS {
		err = errors.New(resp.ResponseDesc)
		return
	}
	return
}

func (s *StanpayNg) SetPrivateKey(key string) StanPayNgService {
	s.privateKey = key
	return s
}

func (s *StanpayNg) SetPublicKey(Key string) StanPayNgService {
	s.publicKey = Key
	return s
}

func (s *StanpayNg) getPrivateKey() string {
	if s.privateKey == "" {
		return _privateKey
	}
	return s.privateKey
}

func (s *StanpayNg) getPublicKey() string {
	if s.publicKey == "" {
		return _itsPubKeyStr
	}
	return s.publicKey
}

func (s *StanpayNg) SetPaymentUrl(url string) StanPayNgService {
	if strings.TrimSpace(url) != "" {
		s.paymentUrl = url
	}
	return s
}

func (s *StanpayNg) SetDisbursementUrl(url string) StanPayNgService {
	if strings.TrimSpace(url) != "" {
		s.disbursementUrl = url
	}
	return s
}
